class State(object):
  "A State is a pause point inside a Machine."
  def __init__(self,name) :
    """
    States have a text 'name' and list of 'outs' Acts. For effeciency
    reasons, this list is sorted decreasing on Act priority order.
    The sum of all Act priorities in 'outs' is 'totalProbs'.
    """    
    self.name = name
    self.outs = []
    self.totalProb = 0
    self.flags(name)

  def flags(self,name) :
    """
    States have flags 'isEndState', 'isErrorState', 'isProgressState'.
    These are set from special symbols in the state name.
    """
    self.isEndState      = '.' in name
    self.isErrorState    = '_' in name
    self.isProgressCycle = '#' in name

  def out(self,act) :
    "When we add an act to 'outs', we update 'totalProb' and re-sort."
    self.outs.append(act)
    self.totalProb += act.priority
    self.outs.sort(key = lambda x: -1*x.priority)
    return act

  def todo(self,lives) :
    """
    Search 'outs' for an Act that is ready to fire. This search is
    biased by Act priorities.
    """
    while lives > 0 :
      for one in often(self.outs,self.totalProb,
                       lambda x:x,
                       lambda x:x.priority):
        if one.ready():
          return one
      lives -= 1
    return None

  def onEntry(self,act,w) :
    "On entry to a state, do something."
    w.steps += 1
    print "Entering >>",self.name ,\
          ' ('+act.tag+')',"-" * w.steps
  def onExit(self,act,w) :
    "On exit from a state, do something."
    1

  def goOn(self,act,w) :
    "Returns false if we are at error or end state, or if we are looping."
    n = inc(w.visited,self.name)
    if self.isErrorState:
      print "oops"
      return False
    if self.isEndState:
      print "done"
      return False
    if self.looping(n) :
      print "oops looping"
      return False
    return True

  def looping(self,n) :
    "We are looping if this is not a progress cycle and we've been here before."
    return  n > 1 and not self.isProgressCycle

  def __repr__(self) :
    "Pretty print this object."
    return '<' + str(self.name) + '> : ' + str(len(self.outs))

